<!doctype HTML>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1" />
<title>ThinkPHP模块开发</title>
<style>
body {
color: #333;
font-family: sans-serif;
font-size: 12pt;
line-height: 170%;
padding: 0 30px 0 270px;
}

header .banner {
margin: 0 0 1em 0;
}

header .banner, nav .banner {
color: #777;
font-size: 10pt;
font-weight: bold;
}

header h1 {
background: #0c3;
border-radius: 4px;
color: #fff;
font-size: 24pt;
margin: 0;
padding: 1.2em 0;
text-align: center;
}

nav {
font-size: 10pt;
overflow-x: auto;
overflow-y: auto;
position: fixed;
top: 0;
left: 0;
bottom: 0;
width: 240px;
}

nav .menubar {
border-bottom: solid 1px #ccc;
display: none;
height: 48px;
line-height: 48px;
padding: 0 10px;
}

nav .button {
background: #777;
border: 1px solid #333;
color: #fff;
font-size: 10pt;
font-weight: bold;
padding: 8px;
border-radius: 4px;
}

nav ul {
padding: 0 0 0 10px;
}

nav ul a {
color: #333;
text-decoration: none;
}

nav ul a:hover {
text-decoration: underline;
}

nav li {
line-height: 180%;
list-style: none;
margin: 0;
padding: 0;
}

nav .level2 {
font-size: 11pt;
font-weight: bold;
}

nav .level3 {
padding-left: 1em;
}

nav .level3:before { 
content: "» ";
}

nav .level4 {
padding-left: 2em;
}

nav .level4:before {
content: "› ";
}

article h2 {
border-bottom: dotted 1px #777;
font-size: 20pt;
line-height: 100%;
margin: 2em 0 1em 0;
padding: 0 0 0.3em 0;
}

article h3 {
font-size: 12pt;
height:50px;
line-height: 50px;
margin: 2em 0 1em 0;
padding-left:20px;
background:#cccccc;
}

article h4 {
font-size: 12pt;
font-style:italic;
font-weight: normal;
line-height: 100%;
margin: 1.2em 0 1em 0;
padding: 0;
}

article p {
margin: 1em 0;
}

article p code {
background: #eee;
border: 1px solid #ccc;
}

article p strong {
color: #f00;
}

article pre {
background: #eee;
border-left: solid 2px #3c0;
font-size: 10pt;
margin: 1em 0;
padding: 0 0 0 1em;
overflow-x: auto;
overflow-y: padding;
}

article blockquote {
background: #fff;
border: dashed 1px #777;
border-left: solid 2px #777;
color: #000;
margin: 0;
padding: 0 0 0 1em;
}

article ul, article ol {
padding-left: 2em;
}

article img{height:400px;width:auto;}

footer {
border-top: 1px solid #ccc;
font-size: 10pt;
margin-top: 4em;
}

@media (max-width: 768px) {

body {
padding: 0 10px 0 230px;
}

nav {
width: 230px;
}

}

@media (max-width: 480px) {

body {
padding: 64px 10px 0 10px;
}

header .banner {
display: none;
}

nav {
position: absolute;
width: 100%;
}

nav .menubar {
display: block;
}

nav .banner {
float: right;
}

nav ul {
background: #fff;
display: none;
font-size: 14pt;
margin: 0;
padding: 0 0 0 8px;
}

nav .level2 {
font-size: 16pt;
font-weight: bold;
}

nav li {
line-height: 240%;
}

.index nav ul {
display: block;
}

.index article {
display: none;
}

}
</style>
<script>
  (function (tags) {
    var i = 0, len = tags.length;

    for (; i < len; ++i) {
        document.createElement(tags[i]);
    }
  }([ 'header', 'nav', 'article', 'footer' ]));
</script>
</head>
<body>
<header>
<h1 id="-thinkphp-">龙之翼 ThinkPHP模块分析 开发文档</h1>

</header>
<nav>
<div class="menubar">
<a class="button">&#9776;&nbsp;索引</a>
</div>
<ul>
<li class="level2"><a href="#1">模块分析前言</a></li><li class="level3"><a href="#1.1">我们的主旨</a></li><li class="level3"><a href="#1.2">做模块的意义</a></li><li class="level2"><a href="#2">安装模块</a></li><li class="level3"><a href="#2.1">index.php</a></li><li class="level3"><a href="#2.2">install.php</a></li><li class="level3"><a href="#2.3">index.html</a></li><li class="level3"><a href="#2.4">step1.html</a></li><li class="level3"><a href="#2.5">step2.html</a></li><li class="level3"><a href="#2.6">step3.html</a></li><li class="level3"><a href="#2.7">complete.html</a></li><li class="level3"><a href="#2.8">IndexController.class.php</a></li><li class="level4"><a href="#2.8.1">1.结构</a></li><li class="level4"><a href="#2.8.2">2、安装首页 <code>public function index()</code></a></li><li class="level4"><a href="#2.8.3">3、安装完成 <code>public function complete()</code></a></li><li class="level3"><a href="#2.9">InstallController.class.php</a></li><li class="level4"><a href="#2.9.1">1、结构</a></li><li class="level4"><a href="#2.9.2">2.检测环境 public function step1()</a></li><li class="level4"><a href="#2.9.3">3.创建数据库 public function step2($db=null,$admin=null)</a></li><li class="level4"><a href="#2.9.4">4.安装数据表 public function step3()</a></li></ul>

</nav>
<article>
<h2 id="1">模块分析前言</h2>
<h3 id="1.1">我们的主旨</h3>
<p>　　我们的主旨是：打造公司一流的产品！</p>
<p>　　目前互联网的产品实在太多，不管是开源产品，还是非开源产品，我们会发现，很多产品没有一个良好的生态。</p>
<p>　　因为ThinkPHP在国内的基因非常良好，一方面，我们借鉴互联网的一部分产品融合到我们的产品当中；另一方面，我们将循着产品的良好生态认真地发展下去！</p>
<h3 id="1.2">做模块的意义</h3>
<p>　　我们会发现，在开发展过程中，一部分产品被开发出来了，过了一段时间无人问津，甚至永远无人访问，甚至里边有一些良好的模块也再没有用到，甚至到下一次开发的时候，我们还敷用到了相同的模块！那么，我们开发了那么长时间的产品，花了那么多的人力与金钱，永远就这样消亡下去了吗？</p>
<p>　　正确的方式是怎样的呢？我认为，每一次产品与上一次产品，大部分有50-80%的功能都是相同的！那么，既然这样，我们就可以将上一次开发出来的一些模块剥离出来，在下一次的开发过程中运用！可以说相同部分，直接复制过来就可以无缝的运用，这样会是一个非常完美的想法！</p>
<p>　　那么事实是这样吗？我们这一次就要做这样的工作！希望我们会做的更好！！！</p>

<h2 id="2">安装模块</h2>
<p>　　很多时候，有的程序员认为安装模块没有什么意义，其实你在研究安装模块的过程中，你就会发现，其实很多配置文件，数据库安装的思维过程，甚至文件的读写方式（或者说是系统环境）就决定了你使用过程是否顺利！</p>
<h3 id="2.1">index.php</h3>
<p>代码如下：</p>
<pre><code>&lt;?php
if(version_compare(PHP_VERSION,&#39;5.3.0&#39;,&#39;&lt;&#39;))  die(&#39;require PHP &gt; 5.3.0 !&#39;);
define(&#39;APP_DEBUG&#39;,true);
define(&#39;APP_PATH&#39;,&#39;./Application/&#39;);
if(!is_file(APP_PATH . &#39;Install/Data/install.lock&#39;)){
    header(&#39;Location: ./install.php&#39;);
    exit;
}
require &#39;./ThinkPHP/ThinkPHP.php&#39;;</code></pre>
<p>详细说明</p>
<p><code>if(version_compare(PHP_VERSION,&#39;5.3.0&#39;,&#39;&lt;&#39;))  die(&#39;require PHP &gt; 5.3.0 !&#39;);</code>  </p>
<p><code>PHP_VERSION</code> 指的是PHP的版本</p>
<p><code>version_compare</code> 指的是比较PHP版本</p>
<p>这一句是说：如果PHP版本小于 5.3.0 就显示 <code>&#39;require PHP &gt; 5.3.0 !&#39;</code></p>
<p><code>define(&#39;APP_DEBUG&#39;,true);</code> 开启调试模式 建议开发阶段开启 部署阶段注释或者设为<code>false</code></p>
<p><code>define(&#39;APP_PATH&#39;,&#39;./Application/&#39;);</code> 定义 <code>APP_PATH</code> 为一个常量，其值为 <code>./Applicaiton/</code></p>
<pre><code>if(!is_file(APP_PATH . &#39;Install/Data/install.lock&#39;)){
    header(&#39;Location: ./install.php&#39;);
    exit;
}</code></pre>
<p>在<code>index.php</code>文件中，检测是否有安装文件<code>install.lock</code>文件，如果有，则退出；如果没有，则跳转到<code>install.php</code>文件。</p>
<p><code>require &#39;./ThinkPHP/ThinkPHP.php&#39;;</code>引用 ThinkPHP.php 文件。</p>
<h3 id="2.2">install.php</h3>
<pre><code>&lt;?php
if(version_compare(PHP_VERSION,&#39;5.3.0&#39;,&#39;&lt;&#39;))  die(&#39;require PHP &gt; 5.3.0 !&#39;);
$_GET[&#39;m&#39;] = &#39;Install&#39;;
define ( &#39;APP_DEBUG&#39;, true );
define ( &#39;APP_PATH&#39;, &#39;./Application/&#39; );
require &#39;./ThinkPHP/ThinkPHP.php&#39;;</code></pre>
<p>说明：</p>
<p><code>$_GET[&#39;m&#39;] = &#39;Install&#39;;</code> 很明显 <code>$_GET[&#39;m&#39;] = &#39;Install&#39;;</code>  这里的<code>m</code>指的是模块，指的就是 <code>/Applicaiton/</code> 下的 <code>Install</code> 模块目录！！！！！！！</p>
<p><code>$_GET</code> 的用法是PHP中原生方法，不是ThinkPHP中的。</p>
<p><code>$_GET[&#39;m&#39;]=&#39;Install&#39;;</code> 的意思就是在浏览器上加一句链接，比如目前是 <code>http://localhost/install.php</code>，我加这么一句话的意思就是在这个链接上加上一个词，链接就变成下边的链接了<code>http://localhost/install.php/Install</code> 。
这一句的意思很明显，直接调用 <code>Install</code> 模块。
这一句很简单，却相当重要!!!一下就看出了作者的水平。
一般人都会 <code>header()</code> 直接跳转到安装目录，
如 <code>header(&#39;Location:./index.php/Install&#39;);</code> 
或者 <code>header(&#39;Location:./install.php/Install&#39;);</code> 
或者采用 <code>rewrite模式</code>，即  <code>&#39;URL_MODEL&#39; =&gt;2就会用 header(&#39;Location:./Install/&#39;);</code> 
或者采用其他格式
标准URL格式如下： <code>http://serverName/index.php/模块/控制器/操作</code>
链接： <code>http://document.thinkphp.cn/manual_3_2.html#url</code></p>
<p>1、普通模式：<br><code>http://localhost/?m=home&amp;c=user&amp;a=login&amp;var=value</code><br>可更改为：<br><code>http://localhost/?module=home&amp;controller=user&amp;action=login&amp;var=value</code>    </p>
<p>2、PATHINFO模式：<br><code>http://localhost/index.php/home/user/login/var/value/</code><br>可更改为：<br><code>http://localhost/index.php/home/user/login?var=value</code><br>或者<br><code>http://localhost/index.php/home-user-login-var-value</code></p>
<p>3、REWRITE模式：<br>加上<code>.htaccess</code>文件就可以用下边的模式     <code>http://localhost/home/user/login/var/value</code>  </p>
<p>4、兼容模式：<br><code>http://localhost/?s=/home/user/login/var/value</code><br>可更改为：<br><code>http://localhost/?path=/home-user-login-var-value</code>  </p>
<h3 id="2.3">index.html</h3>
<p>说明：首先调用这个文件，显示首页：开源安装协议！！<br><code>\Application\Install\View\Index\index.html</code></p>
<h3 id="2.4">step1.html</h3>
<p>说明：环境检测<br><code>\Application\Install\View\Install\step1.html</code></p>
<h3 id="2.5">step2.html</h3>
<p>说明：创建数据库<br><code>\Application\Install\View\Install\step2.html</code></p>
<h3 id="2.6">step3.html</h3>
<p>说明：安装数据库<br><code>\Application\Install\View\Install\step3.html</code></p>
<h3 id="2.7">complete.html</h3>
<p>说明：完成安装<br><code>\Application\Install\View\Index\complete.html</code></p>
<h3 id="2.8">IndexController.class.php</h3>
<p>说明：这个文件主要有两个函数 <code>public function index()</code> 和 <code>public function complete()</code> 这两个函数。</p>
<p>下边细讲：</p>
<h4 id="2.8.1">1.结构</h4>
<pre><code>&lt;?php
namespace Install\Controller;
use Think\Controller;
use Think\Storage;

class IndexController extends Controller{
    //安装首页
    public function index(){
    }

    //安装完成
    public function complete(){
    }
}</code></pre>
<p>1.1、<br>这一句 <code>namespace Install\Controller;</code>
这是系统的规范要求，表示当前类是<code>Install</code>模块下的控制器类，命名空间和实际的控制器文件所在的路径是一致的，<br>也就是说： <code>Install\Controller\IndexController</code> 类 对应的控制器文件位于应用目录下面的 <code>Install/Controller/IndexController.class.php</code>，如果你改变了当前的模块名，那么这个控制器类的命名空间也需要随之修改。   </p>
<p><code>use Think\Controller;</code> 表示引入 <code>Think\Controller</code> 命名空间便于直接使用。 所以，</p>
<pre><code>use Think\Controller;
class IndexController extends Controller{}</code></pre>
<p>等同于使用：</p>
<pre><code>class IndexController extends \Think\Controller{}</code></pre>
<p>1.2、<br><code>use Think\Storage</code><br>这个文件在 <a href="http://document.thinkphp.cn/manual_3_2.html#storage_driver">http://document.thinkphp.cn/manual_3_2.html#storage_driver</a> 这个链接下，<br><code>Storage</code>叫存储驱动！存储驱动完成了不同环境下面的文件存取操作，也是ThinkPHP支持分布式和云平台的基础。
默认的存储驱命名空间位于Think\Storage\Driver,每个存储驱动必须继承Think\Storage。</p>
<h4 id="2.8.2">2、安装首页 <code>public function index()</code></h4>
<p>源代码：</p>
<pre><code>//安装首页
public function index(){
    if(Storage::has(MODULE_PATH . &#39;Data/install.lock&#39;)){
        $this-&gt;error(&#39;已经成功安装了里程密，请不要重复安装!&#39;);
    }
    session_destroy();
    session_start();
    session(&#39;step&#39;, 0);
    session(&#39;error&#39;, false);
    $this-&gt;display();
}</code></pre>
<p>2.1<br><code>if(Storage::has(MODULE_PATH . &#39;Data/install.lock&#39;))</code><br>存储驱动查询路径下是否有 <code>install.lock</code> 文件。<code>has</code>为查询！   </p>
<p>2.2<br><code>session_destroy();</code><br>删除当前用户对应的<code>session</code>以及释放<code>session</code>。因为以前有很多用户可能存在<code>session</code>，会影响当前用户的使用！因此，需要先删除<code>session</code>，再重新开始新的<code>session</code>。
注意：<br>这里用的 <code>session_destroy()</code> 为PHP自带的函数，而 <code>ThinkPHP</code> 带的删除<code>session</code>函数为：<code>session(&#39;[destroy]&#39;);</code><br>当然，在这里两种方式都可以用的！   </p>
<p>2.3<br><code>session_start();</code><br>开始新的<code>session</code>，开始新的<code>session</code>之前，必须先<code>session_start()</code> 开启<code>session</code>。这样就可以对<code>session</code>进行赋值与取值了!<br>注意：这里用的<code>session_start()</code> 为PHP自带的函数，而<code>ThinkPHP</code>带的开启<code>session</code>函数为： <code>session(&#39;[start]&#39;);</code><br>当然，在这里两种方式都可以用的！</p>
<p>2.4<br><code>session(&#39;step&#39;, 0);session(&#39;error&#39;, false);</code>   </p>
<ul>
<li><p>本来PHP正常的步骤是这样<code>session_start();</code> 之后采用 <code>$_SESSION[&#39;user&#39;]=&#39;hongwei&#39;;</code> 赋值，然后输出相应的<code>session</code>值。如：<code>echo $_SESSION[&#39;user&#39;];</code> 其返回值就为 <code>hongwei</code>。   </p>
</li>
<li><p><code>session</code>这个值是在 <code>Thinkphp</code> 为了方便给内置了一个<code>session</code>函数。<br>在官方文档里有这样的定义，具体可以看 <a href="http://document.thinkphp.cn/manual_3_2.html#session">http://document.thinkphp.cn/manual_3_2.html#session</a> 。如果想要操作的话，可以看文档。官方是这样定义<code>session</code>的 <code>session(array(&#39;name&#39;=&gt;&#39;session_id&#39;,&#39;expire&#39;=&gt;3600));</code>  </p>
</li>
<li><p><code>session(&#39;step&#39;, 0); session(&#39;error&#39;, false);</code>用Thinkphp这样定义<code>session</code>后，这样就定义了两个<code>session</code>。一个名为<code>step</code>，其值为<code>0</code>；一个名为<code>error</code>，其值为 <code>false</code>。
这两个<code>session</code>有什么作用呢？在后边会用到！   </p>
</li>
<li><p>重点：那么在TP中的php文件中和在html文件中，怎样取出来<code>session</code>呢？</p>
</li>
</ul>
<p>在PHP中这样取出值<br>方法一：<code>echo  session(&#39;step&#39;);</code>   Thinkphp的取值方式，这里是 <code>圆括号</code><br>方法二：<code>echo $_SESSION[&#39;step&#39;];</code>  PHP的取值方式，这里是 <code>方括号</code>    </p>
<p>在HTML中这样取值
方法一：<code>{$Think.session.step}</code>   Thinkphp的取值方式<br>方法二：<code>{$_SESSION[&#39;step&#39;]</code>      PHP的取值方式   </p>
<p><code>$this-&gt;display();</code>
当然，这里的显示的是 <code>/Application/Install/View/Index/index.html</code>  这一个文件。</p>
<p>index函数总结
这个函数其实就判断是否有<code>install.lock</code>文件，然后清除<code>session</code>。   </p>
<h4 id="2.8.3">3、安装完成 <code>public function complete()</code></h4>
<p>源代码：   </p>
<pre><code>//安装完成
public function complete(){
    $step = session(&#39;step&#39;);

    if(!$step){
        $this-&gt;redirect(&#39;index&#39;);
    } elseif($step != 3) {
        $this-&gt;redirect(&quot;Install/step{$step}&quot;);
    }

    Storage::put(MODULE_PATH . &#39;Data/install.lock&#39;, &#39;lock&#39;);
    //创建配置文件
    $this-&gt;assign(&#39;info&#39;,session(&#39;config_file&#39;));

    session(&#39;step&#39;, null);
    session(&#39;error&#39;, null);
    $this-&gt;display();
}</code></pre>
<p>3.1<br><code>$step = session(&#39;step&#39;);</code><br>以正常的方式这里输出值为 <code>$step=3</code><br>
3.2<br>    if(!$step){
        $this-&gt;redirect(&#39;index&#39;);
    } elseif($step != 3) {
        $this-&gt;redirect(&quot;Install/step{$step}&quot;);
    }</p>
<p>如果$step没有值的话跳到首页，如果$step的值不等于3的话，就跳到相应的步骤！<br>这一点会在<code>InstallController.class.php</code>体现出来！   </p>
<p>3.3<br><code>Storage::put(MODULE_PATH . &#39;Data/install.lock&#39;, &#39;lock&#39;);</code><br><code>Storage</code>为存储驱动，<code>put</code>为 “写文件” ，这一步的作用是：安装完成了，我要在Data下写入一个文件 install.lock。里边写内容为 lock。</p>
<p>3.4<br><code>$this-&gt;assign(&#39;info&#39;,session(&#39;config_file&#39;));</code>   </p>
<ul>
<li><p><code>session(&#39;config_file&#39;)</code> 这个在 <code>InstallController.class.php</code> 文件中定义过，这里直接取出！   </p>
</li>
<li><p><code>$this-&gt;assign(&#39;info&#39;,session(&#39;config_file&#39;));</code><br>这里直接为 <code>info</code> 赋值为 <code>session(&#39;config_file&#39;)</code> ，然后直接在 模板中调用出来！</p>
</li>
<li><p><code>session(&#39;step&#39;, null);   session(&#39;error&#39;, null);</code><br>这里将清空 <code>session</code>的<code>step</code>与<code>error</code>值。</p>
</li>
<li><p><code>$this-&gt;display();</code><br>这里显示安装完成的页面。其页面在 <code>/Application/Install/View/Index/Complete.html</code> 这个文件中。   </p>
</li>
</ul>
<h3 id="2.9">InstallController.class.php</h3>
<h4 id="2.9.1">1、结构</h4>
<p>代码如下：</p>
<pre><code>&lt;?php
namespace Install\Controller;
use Think\Controller;
use Think\Db;
use Think\Storage;

class InstallController extends Controller{

    //初始化
    protected function _initialize(){
    }

    //安装第一步，检测运行所需的环境设置
    public function step1(){
    }

    //安装第二步，创建数据库
    public function step2($db = null, $admin = null){    
    }

    //安装第三步，安装数据表，创建配置文件
    public function step3(){
    }
}</code></pre>
<p>1.1<br><code>use Think\Db;</code><br><code>Think\Db</code> 表示数据库驱动，默认的数据库驱动位于 <code>Think\Db\Driver</code>命名空间下面，驱动类必须继承 <code>Think\Db</code>类。<br>详见 <a href="http://document.thinkphp.cn/manual_3_2.html#db_driver">http://document.thinkphp.cn/manual_3_2.html#db_driver</a> </p>
<p>1.2<br>初始化 <code>protected function _initialize()</code></p>
<p>源代码：</p>
<pre><code>protected function _initialize(){
    if(session(&#39;step&#39;) === null){
        $this-&gt;redirect(&#39;Index/index&#39;);
    }

    if(Storage::has(MODULE_PATH . &#39;Data/install.lock&#39;)){
        $this-&gt;error(&#39;已经成功安装了里程密，请不要重复安装!&#39;);
    }
}</code></pre>
<p>1.2.1<br><code>protected</code><br><code>public</code>:权限是最大的，可以内部调用，实例调用等。<br><code>protected</code>: 受保护类型，用于本类和继承类调用。<br><code>private</code>: 私有类型，只有在本类中使用。<br>实例请看 <a href="http://blog.163.com/wz_pk007/blog/static/170627050201143104938560/">http://blog.163.com/wz_pk007/blog/static/170627050201143104938560/</a></p>
<p><code>protected function _initialize()</code><br>1、<code>__initialize()</code> 不是php类中的函数，php类的构造函数只有 <code>__construct()</code>。<br>2、类的初始化：子类如果有自己的构造函数 <code>__construct()</code> ,则调用自己的进行初始化，如果没有，则调用父类的构造函数进行自己的初始化。
3、当子类和父类都有 <code>__construct()</code> 函数的时候，如果要在初始化子类的时候同时调用父类的 <code>__constrcut()</code>，则可以在子类中使用 <code>parent::__construct()</code> 。<br>4、<code>_initialize()</code> 函数是在任何方法执行之前，都要执行的，当然也包括 <code>_ _construct</code> 构造函数，注意，<code>__construct</code> 这里是双划线，而<code>_initialize()</code>函数是单划线。<br>5、如果父子类均有 <code>_initialize()</code>函数，则子类覆盖了父类的，如果子类没有而父类有，则子类继承父类的。在调用子类对象的 <code>_initialize()</code> 时，不会导致自动调用父类的 <code>_initialize()</code>。<br>6、默认情况下，子类的构造函数也不会自动调用父类的构造函数，这一点与Java不同。实际编写子类的构造函数时，一般都要加上父类构造函数的主动调用 <code>parent::_ _construct()</code>，否则会导致子类对象空指针的异常，如 <code>Call to a member function assign() on a non-object</code> 。<br>7、<code>_initialize()</code> 函数是在“任何”方法调用之前都要调用的，也就是说如果存在 <code>_initialize()</code> 函数，调用对象的任何方法都会导致 <code>_initialize()</code> 函数的自动调用，而_ <code>_construct</code>构造函数仅仅在创建对象的时候调用一次，跟其它方法调用没有关系。  </p>
<p>1.2.2    </p>
<pre><code>if(session(&#39;step&#39;) === null){
    $this-&gt;redirect(&#39;Index/index&#39;);
}</code></pre>
<p>1.2.2.1<br>三个等号：<br>=：赋值，在逻辑运算时也有效；<br>==：等于运算，但是不比较值的类型；<br>===：完全等于运算，不仅比较值，而且还比较值的类型，只有两者一致才为真。  </p>
<p>1.2.2.2<br>如果 <code>session(&#39;step&#39;)</code> 等于 <code>null</code> ,也就是被 <code>session(&#39;step&#39;,null)</code> 后之后，直接跳转  </p>
<p>1.2.2.3<br>在ThinkPHP中，用 <code>$this-&gt;redirect</code> 进行跳转！</p>
<p>1.3<br><code>MODULE_PATH</code>  这个是系统常量，指的是当前模块路径，这里用 <code>echo MODULE_PATH;</code> 得到模块路径是： <code>./Application/Install/</code> 。</p>
<h4 id="2.9.2">2.检测环境 public function step1()</h4>
<p>源代码：  </p>
<pre><code>//安装第一步，检测运行所需的环境设置
public function step1(){
    session(&#39;error&#39;, false);

    //环境检测
    $env = check_env();

    //目录文件读写检测
    if(IS_WRITE){
        $dirfile = check_dirfile();
        $this-&gt;assign(&#39;dirfile&#39;, $dirfile);
    }

    //函数检测
    $func = check_func();

    session(&#39;step&#39;, 1);

    $this-&gt;assign(&#39;env&#39;, $env);
    $this-&gt;assign(&#39;func&#39;, $func);
    $this-&gt;display();
}</code></pre>
<p>2.1<br>session(&#39;error&#39;,false);<br>设置<code>session</code>为<code>error</code>，值为<code>false</code>。</p>
<p>2.2<br>$env=check_env(); 
这个是检测环境的函数。这个函数在 <code>/Application/Install/Common/function.php</code> 函数中<br><code>function check_env()</code> 这个函数有5个作用：PHP环境检测、数据库检测（PHP5.5不支持MySQL检测）、附件上传检测、GD库检测、磁盘空间检测。</p>
<p>2.3<br>    //目录文件读写检测
    if(IS_WRITE){
        $dirfile = check_dirfile();
        $this-&gt;assign(&#39;dirfile&#39;, $dirfile);
    }</p>
<p><code>IS_WRITE</code><br>首先要注意的是，<code>IS_WRITE</code> 这是一个常量 ，用来“检测环境是否支持可写”，这个函数也是在 <code>/Application/Install/Common/function.php</code> 函数中，如下：<br><code>define(&#39;IS_WRITE&#39;,APP_MODE !== &#39;sae&#39;);</code>
这一句是什么意思？我也没看懂 <code>APP_MODE!=’sae’</code></p>
<p>2.4<br><code>$func = check_func();</code>  </p>
<p>函数检测，这个函数也是在 <code>/Application/Install/Common/function.php</code> 函数中：<br>用来检测 mysql_connect，file_get_contents，mb_strlen 这三个函数的是否可用！</p>
<h4 id="2.9.3">3.创建数据库 public function step2($db=null,$admin=null)</h4>
<p>源代码：</p>
<pre><code>//安装第二步，创建数据库
public function step2($db = null, $admin = null){
   if(IS_POST){
      //检测管理员信息
      if(!is_array($admin) || empty($admin[0]) || empty($admin[1]) ){
         $this-&gt;error(&#39;请填写完整管理员信息&#39;);
      } else if($admin[1] != $admin[2]){
         $this-&gt;error(&#39;确认密码和密码不一致&#39;);
      } else {
         $info = array();
               list($info[&#39;username&#39;], $info[&#39;password&#39;], $info[&#39;repassword&#39;]) = $admin;

         //缓存管理员信息
         session(&#39;admin_info&#39;, $info);
      }

      //检测数据库配置
      if(!is_array($db) || empty($db[0]) ||  empty($db[1]) || empty($db[2]) || empty($db[3])){
         $this-&gt;error(&#39;请填写完整的数据库配置&#39;);
      } else {
         $DB = array();
         list($DB[&#39;DB_TYPE&#39;], $DB[&#39;DB_HOST&#39;], $DB[&#39;DB_NAME&#39;], $DB[&#39;DB_USER&#39;], $DB[&#39;DB_PWD&#39;],
             $DB[&#39;DB_PORT&#39;], $DB[&#39;DB_PREFIX&#39;]) = $db;
         //缓存数据库配置
         session(&#39;db_config&#39;, $DB);

         //创建数据库
         $dbname = $DB[&#39;DB_NAME&#39;];
         unset($DB[&#39;DB_NAME&#39;]);
         $db  = Db::getInstance($DB);
         $sql = &quot;CREATE DATABASE IF NOT EXISTS `{$dbname}` DEFAULT CHARACTER SET utf8&quot;;
         $db-&gt;execute($sql) || $this-&gt;error($db-&gt;getError());
      }

      //跳转到数据库安装页面
      $this-&gt;redirect(&#39;step3&#39;);
   } else {

      session(&#39;error&#39;) &amp;&amp; $this-&gt;error(&#39;环境检测没有通过，请调整环境后重试！&#39;);

      $step = session(&#39;step&#39;);
      if($step != 1 &amp;&amp; $step != 2){
         $this-&gt;redirect(&#39;step1&#39;);
      }

      session(&#39;step&#39;, 2);
      $this-&gt;display();
   }
}</code></pre>
<p>3.1<br><code>if(IS_POST){} else {}</code><br>说明：<code>IS_POST</code>是ThinkPHP中的函数。用来检测是否本地提交！  </p>
<p>3.2<br><code>$this-&gt;error(&#39;请填写完整管理员信息&#39;);</code><br>说明：这里弹出的提示框非常漂亮，如下图，是采用了 <code>sweetalert.css</code> 的方式！很漂亮的！以前的文件是用了超链接的形式 <code>www.lcm.wang</code>，然后我把文件放在了<code>ThinkPHP/Tpl/jquery,ThinkPHP/Tpl/sweetalert.css</code>里了！<code>sweetalert.css</code> 会单独讲！</p>
<p>3.3<br><code>if(!is_array($admin) || empty($admin[0]) || empty($admin[1]) ){$this-&gt;error(&#39;请填写完整管理员信息&#39;);}</code><br>说明，这里写的非常不错，没有数据库，form 表单里都加的是 数组形式，如下，<code>name</code>都是  <code>admin[]</code></p>
<p>用户名：<code>&lt;input type=&quot;text&quot; name=&quot;admin[]&quot; value=&quot;admin&quot;&gt;</code><br>密码：<code>&lt;input type=&quot;password&quot; name=&quot;admin[]&quot; value=&quot;admin&quot;&gt;</code><br>确认密码：<code>&lt;input type=&quot;password&quot; name=&quot;admin[]&quot; value=&quot;admin&quot;&gt;</code>  </p>
<p>因此，<code>name</code>的值可以填相同名称，也可以填不同名称。   </p>
<p>a.填相同的名称<br>PHP文件文件就这样调用 ，先声明，后 调用！！
声明：<code>public function step2($db = null, $admin = null)</code>
调用：<code>$admin,$admin[0] , $admin[1]</code>  等等这样调用</p>
<p>b.填不相同的名称
调用的时候打印 <code>$_POST[&#39;username&#39;]</code> 这样来调用！！</p>
<p>3.4<br><code>if($admin[1] != $admin[2]){$this-&gt;error(&#39;确认密码和密码不一致&#39;);}</code><br>说明：密码与确认密码！</p>
<p>3.5<br><code>$info = array();  list($info[&#39;username&#39;], $info[&#39;password&#39;], $info[&#39;repassword&#39;]) = $admin;</code><br>说明：我觉得这一步作者特别有水平，将 <code>$admin</code> 的参数分别赋值给 <code>$ino[&#39;username&#39;],$info[&#39;password&#39;]</code> 和 <code>$info[&#39;repassword&#39;]</code> 等。</p>
<p>3.6<br><code>session(&#39;admin_info&#39;, $info);</code><br>紧接着，作者定义<code>session</code>，将<code>$info</code>的信息赋值给 <code>admin_info</code>;<br>有人说，怎么调用 这个<code>session</code>呢？其实也很简单啊！  </p>
<p>1、PHP调用方法<br><code>$_SESSION[&#39;admin_info&#39;][&#39;username&#39;];</code>    注意：这里是<code>方括号</code>，每一个都要用引号。</p>
<p>2、THINKPHP调用方法
<code>Session(&#39;admin_info.username&#39;);</code>  注意：这里是<code>一个大圆括号</code>，而且必须要用引号！</p>
<p>3.7<br><code>$dbname = $DB[&#39;DB_NAME&#39;];  unset($DB[&#39;DB_NAME&#39;]);</code><br>说明：<code>unset</code> 是 销毁指定的变量。这里的意思是销毁 <code>$DB[&#39;DB_NAME&#39;];</code>  因为之前已经定义 <code>$dbname</code> ，这里的意思是以后要用 <code>$dbname</code> 这个变量了，不用 <code>$DB[&#39;DB_NAME&#39;]</code>，不要让这两个冲突了！销毁其中一个变量就OK了！</p>
<p>3.8<br><code>$db  = Db::getInstance($DB);</code><br><code>getInstance</code> 这个函数是在  <code>\ThinkPHP\Library\Behavior\ChromeShowPageTraceBehavior.class.php</code>  定义的，如下：  </p>
<pre><code>public static function getInstance()
{
    if (self::$_instance === null) {
        self::$_instance = new self();
    }
    return self::$_instance;
}</code></pre>
<p>3.8.1<br>这个函数的作用是：<code>Db::getInstance($DB);</code> 就可以实例化数据库了！这个在项目中也常用到！<code>$DB</code> 的信息就包括：数据库网址，用户名，密码。<br>实例化数据库！然后建立连接，下一步变开始执行SQL建立数据库！打印数据库的配置信息，如下：<br>（顺便打印有 <code>unset</code> 与没有 <code>unset</code> 的区别）。  </p>
<p>3.8.2<br><code>$sql = &quot;CREATE DATABASE IF NOT EXISTS</code>{$dbname}<code>DEFAULT CHARACTER SET utf8&quot;;</code><br>说明：<br>这一句本身不难，就是 建数据库！但是出来一个 <code>{$dbname}</code> 这样的写法，就很特殊了！<br>本身应该这么写  <code>$sql = &quot;CREATE DATABASE IF NOT EXISTS</code>&quot;. $dbname .&quot;<code>DEFAULT CHARACTER SET utf8&quot;;</code><br>看来作者在 ThinkPHP框架中对PHP文件字符串的变量，可以用大括号加变量输出！
下边是打印输出的结果，可以看一下！</p>
<p>PHP文件：  </p>
<p>输出的结果一样：  </p>
<p>3.8.3<br><code>$db-&gt;execute($sql) || $this-&gt;error($db-&gt;getError());</code><br>说明：<br>1、<code>$db-&gt;execute</code> 这个意思是执行 sql 语句！ 上边<code>getInstance</code>后，就可以执行了！
2、<code>||</code> 两竖线表示 “或者”，一开始我还以为作者写错了，原来是正确的！就是 要不执行，要不报数据库的错误。
3、<code>$this-&gt;error($db-&gt;getError());</code>  一个是  <code>$this-&gt;error</code> ，一个是 <code>$db-&gt;getError()</code> 。</p>
<p>3.8.4<br><code>$this-&gt;redirect(&#39;step3&#39;);</code><br>说明：<code>redirect</code>转向。</p>
<h4 id="2.9.4">4.安装数据表 public function step3()</h4>
<p>源代码：</p>
<pre><code>//安装第三步，安装数据表，创建配置文件
public function step3(){
   if(session(&#39;step&#39;) != 2){
      $this-&gt;redirect(&#39;step2&#39;);
   }

   $this-&gt;display();

   //连接数据库
   $dbconfig = session(&#39;db_config&#39;);
   $db = Db::getInstance($dbconfig);

   //创建数据表
   create_tables($db, $dbconfig[&#39;DB_PREFIX&#39;]);

   //注册创始人帐号
   $admin = session(&#39;admin_info&#39;);
   register_administrator($db, $dbconfig[&#39;DB_PREFIX&#39;], $admin);

   //创建配置文件
   $conf  =  write_config($dbconfig);
   session(&#39;config_file&#39;,$conf);
   if(session(&#39;error&#39;)){
      //show_msg();
   } else {
      session(&#39;step&#39;, 3);
      $this-&gt;redirect(&#39;Index/complete&#39;);
   }
}</code></pre>
<p>4.1  </p>
<pre><code>//连接数据库
$dbconfig = session(&#39;db_config&#39;);
$db = Db::getInstance($dbconfig);</code></pre>
<p>说明：<br>第二步已经缓存数据库配置<code>session(&#39;db_config&#39;, $DB);</code>  这一步直接实例化数据库，进行建立数据库。<br>上一步是没有数据库进行实例化，建库；<br>这一步是有数据库进行实例化，建表。  </p>
<p>4.2  </p>
<pre><code>//创建数据表
create_tables($db, $dbconfig[&#39;DB_PREFIX&#39;]);</code></pre>
<p>说明：<br>在函数文件  <code>\Application\Install\Common\function.php</code> 中已经定义创建数据表的函数，<br><code>function create_tables($db, $prefix = &#39;&#39;)</code> 这里两个参数，一个是数据库名称，一个是前缀，因此这样写<br><code>create_tables($db,$dbconfig[&#39;DB_PREFIX&#39;]);</code></p>
<p>这个函数的作用是 把目录下的 <code>\Application\Install\Data\install.sql</code> 安装好！  </p>
<p>4.3  </p>
<pre><code>//注册创始人帐号
$admin = session(&#39;admin_info&#39;);
register_administrator($db, $dbconfig[&#39;DB_PREFIX&#39;], $admin);</code></pre>
<p>说明：<br>首先调用 <code>session</code> 里的 用户名和密码，然后用 函数 <code>register_administrator</code> ，文件在 <code>function.php</code> 中，如下：  </p>
<pre><code>function register_administrator($db, $prefix, $admin){
   show_msg(&#39;开始注册创始人帐号...&#39;);
   $password = md5($admin[&#39;password&#39;]);
   $sql = &quot;INSERT INTO `{$prefix}jingli` (`status`, `username`, `password`) VALUES ( &#39;0&#39;, &#39;{$admin[&#39;username&#39;]}&#39;, &#39;{$password}&#39;)&quot;;
   //执行sql
   $db-&gt;execute($sql);
   show_msg(&#39;创始人帐号注册完成！&#39;);
}</code></pre>
<p>三个参数分别是“数据库”，“数据库前缀”，“管理员名”。</p>
<p>4.4  </p>
<pre><code>//创建配置文件
$conf  =  write_config($dbconfig);</code></pre>
<p>说明：<br>这里是 看 <code>\Application\Admin\Conf\config.php</code> 是否有这一文件，如果没有这个文件，并且这个文件夹，如果可写，就将 <code>\Application\Install\Data\conf.tpl</code>读取，并将<code>session</code>里的数据库七种配置信息一一用<code>str_replace</code>函数替换，再用<code>file_put_contents</code>函数写入文件！
这样就配置完成！</p>
<p>4.5<br><code>session(&#39;step&#39;, 3); $this-&gt;redirect(&#39;Index/complete&#39;);</code><br>说明：<br>设置<code>session</code>为<code>3</code>并转向完成界面！</p>

</article>
<footer>
<p>© 2016 龙之翼网络科技</p>

</footer>
</body>
</html>
